<script setup lang="ts">
import {DataBoard, Monitor, Upload} from "@element-plus/icons-vue";
import {ref, defineProps, onMounted, onUnmounted} from "vue";
import {ElMessage} from "element-plus";
import {useBaseStore} from "@/stores/base.ts";
import {
  MouseClick,
  MouseDoubleClick,
  MouseMove,
  MouseRightClick
} from "../../../../wailsjs/go/view/App";

// 使用 withDefaults 确保类型安全
const props = defineProps({
  wsSendMessage: {
    type: Function,
    required: true
  }
})


const baseStore = useBaseStore()

const localVideo = ref<HTMLVideoElement>();
let peerConnection: RTCPeerConnection | null = null;
let localStream: MediaStream | null = null;
let dataChannel: RTCDataChannel | undefined = undefined
const sdp = ref("")
const ice = ref("")
const rtcStatus = ref()

const clickCreateRoom = async () =>{
  if ( !baseStore.rtcSession.status.wsStatus ){
    ElMessage.warning("ws未连接，无法开启共享操作，请联系管理员！")
    return
  }
  // 1. 页面加载时收集ice；2.点击创建房间时写入记录；3.收到 answer 时将页面状态修改为 rtc ok；4. 点击开始(或者自动点击)开始共享桌面
  // 1. 初始化连接对象，创建offer，收集ice和sdp,发送创建消息。
  // 注意：ICE 候选收集仅在添加媒体轨道后触发。如果你没有添加音频/视频轨道或数据通道，浏览器不会尝试建立连接，因此不会生成候选。
  await initPeerConn();
  await initOffer();
  baseStore.rtcSession.status.rtcStatus = true
  const msg = {type:"createRoom",content:JSON.stringify([sdp.value,ice.value]) }
  props.wsSendMessage(msg)
  baseStore.rtcSession.status.connDescription="等待对方接入"
  baseStore.rtcSession.status.sharing = true
}

// 初始化 peerConn 对象，监听数据流。
// 注意：浏览器版本的 webrtc 只有在本地流加入轨道时才能触发 ice 收集，因此这里直接触发了添加
const initPeerConn = async () =>{
  // 添加本地视频流到轨道中
  localStream = await navigator.mediaDevices.getDisplayMedia({
    video: true,
    audio: baseStore.rtcConfig.openSound
  });
  if (localStream.getVideoTracks().length === 0) {
    // 检查视频轨道
    ElMessage.error("没有视频轨道")
    return;
  }
  if (localVideo.value) {
    // 显示本地视频
    localVideo.value.srcObject = localStream;
  }
  const iceServers:RTCIceServer[] = []
  if ( !baseStore.rtcConfig.onlyLocal ){
    baseStore.rtcConfig.stunAddr.forEach(item =>{
      iceServers.push({ urls: item })
    })
  }
  const configuration: RTCConfiguration = {
    iceServers: iceServers, // 先不是设置中继服务器
  };
  peerConnection = new RTCPeerConnection(configuration);
  // 显示本地流
  if (localStream) {
    localStream.getTracks().forEach(track => {
      peerConnection?.addTrack(track, localStream as MediaStream);
    });
  }
  // ICE candidate 收集
  peerConnection.onicecandidate = (event) => {
    if (event.candidate) {
      const candidate = JSON.stringify(event.candidate);
      console.log("onicecandidate",candidate)
      ice.value = candidate
      rtcStatus.value = true
    }
  };
  // 远程流到达
  peerConnection.ontrack = (event) => {
    // todo 远端流到达时将数据转发给录像服务器
    console.log("ontrack",event)
  };
  // 连接状态变化
  peerConnection.oniceconnectionstatechange = () => {
    if (peerConnection) {
      const state = peerConnection.iceConnectionState;
      console.log("peer conn 状态变化",state)
    }
  }
  createDataChannel()
}
// 初始化 offer,主要收集 ice 和 sdp。因为ice涉及网络调用，所以 ice 收集是设置的一个回调函数，在 createPeerConnection 中触发。
const initOffer = async () =>{
  const offer = await peerConnection?.createOffer();
  await peerConnection?.setLocalDescription(offer);
  sdp.value = JSON.stringify(offer)
  // 等待 ICE candidates 收集
  await new Promise<void>((resolve) => {
    if (peerConnection?.iceGatheringState === 'complete') {
      resolve();
      return;
    }
    const onIceCandidate = (event: RTCPeerConnectionIceEvent) => {
      if (!event.candidate) {
        peerConnection?.removeEventListener('icecandidate', onIceCandidate);
        resolve();
      }
    };
    peerConnection?.addEventListener('icecandidate', onIceCandidate);
    setTimeout(() => {
      peerConnection?.removeEventListener('icecandidate', onIceCandidate);
      resolve();
    }, 100);
  });
}

const setAnswer = async (content:string )=>{
  const params= JSON.parse(content)
  const answer = JSON.parse(params[0])
  peerConnection?.setRemoteDescription( new RTCSessionDescription( answer ))
  // 添加ICE
  const candidate = JSON.parse(params[1]);
  await peerConnection?.addIceCandidate(new RTCIceCandidate(candidate));
  baseStore.rtcSession.status.connDescription="会话持续中..."
}
// 创建 dataChannel
const createDataChannel = ()=>{
  if (dataChannel) return
  dataChannel = peerConnection?.createDataChannel('hcy',{
    ordered: true, // 按顺序发送数据
    maxRetransmits: 5 // 数据发送失败时的重试次数
  })
  dataChannel!.onopen =()=>{
    console.log('DataChannel 已打开')
  }
  dataChannel!.onmessage =(event)=>{
    console.log('DataChannel 收到消息：',event.data)
    handleRemoteCommand(event.data)
  }
  dataChannel!.onclose  =()=>{
    console.log('DataChannel 关闭')
  }
  dataChannel!.onerror  =(err)=>{
    console.log('DataChannel 错误',err)
  }
}
// 处理 dataChannel 传递过来的消息
const handleRemoteCommand = (data:string)=>{
  const command= JSON.parse(data)
  switch (command.type) {
    case "mouse":
      MouseMove(command.x,command.y)
      break
    case "keyDown":
      break
    case "click":
      MouseClick()
      break
    case "doubleClick":
      MouseDoubleClick()
      break
    case "rightClick":
      MouseRightClick()
      break
    default:
      ElMessage.error('未知指令,'+data)
  }
}

onMounted(()=>{
  baseStore.rtcSession.status.title="共享桌面"
  baseStore.rtcSession.status.titleDescription="分享您的屏幕给其他人"
  baseStore.rtcSession.status.connDescription="尚未创建房间"
})

const clickStopSharing=()=>{
  baseStore.rtcSession.status.sharing = false
  baseStore.rtcSession.status.connDescription = "停止共享"
  baseStore.rtcSession.roomId = ""
  // 清理连接 、offer、 和本地媒体流
  if (localStream){
    localStream.getTracks().forEach( track => track.stop() );
    localStream = null
    peerConnection =null
  }
}

onUnmounted(()=>{
  clickStopSharing()
})

const copyToClipboard = async (data:string)=>{
  await navigator.clipboard.writeText(data)
  ElMessage.success("复制成功")
}

defineExpose({
  setAnswer
})
</script>

<template>
  <div  class="h-full">
    <!--      创建房间-->
    <div class="flex flex-col items-center gap-4 ">
      <div class="flex items-center justify-center w-16 h-16 rounded-full bg-gradient-to-br from-purple-100 to-indigo-100">
        <el-icon size="26" color="purple" ><Monitor /></el-icon>
      </div>
      <div class="flex">
        <el-text>创建房间后将生成分享码，等待接收方加入后即可开始桌面共享</el-text>
      </div>
      <div class="flex" v-show="!baseStore.rtcSession.status.sharing">
        <el-button type="primary" :icon="Upload" size="large" @click="clickCreateRoom">创建桌面共享房间</el-button>
      </div>
      <div class="flex justify-center items-center " v-show="baseStore.rtcSession.status.sharing">
        <el-icon size="26" color="green" class="mr-2" ><Monitor /></el-icon>共享中...
        <el-button :icon="DataBoard" type="danger" size="large" class="ml-3" @click="clickStopSharing">停止共享</el-button>
      </div>
    </div>
    <el-divider />
    <div class="flex h-full">
      <div class="inline-flex items-center justify-center w-12 h-12 rounded-lg bg-green-500">
        <el-icon size="20" color="white" ><Monitor /></el-icon>
      </div>
      <div class="inline-block ml-2 h-full">
        <div>
          <p class="font-bold">房间信息</p>
        </div>
        <div class="h-full">
          <el-text>
            房间号：{{baseStore.rtcSession.roomId ==''?'暂无':baseStore.rtcSession.roomId }}
          </el-text>
        </div>
      </div>
    </div>
    <div>
      <el-row >
        <el-col :span="12">
          <div class="h-full">
            <p>本地缩略信息</p>
            <el-card class="h-full">
              <video ref="localVideo" autoplay playsinline class="w-full"></video>
            </el-card>
          </div>
        </el-col>
        <el-col :span="12">
          <div class="h-full">
            <p>房间连接信息</p>
            <el-card class="h-full justify-center">
              <div class="h-full">
                <el-button @click="copyToClipboard(baseStore.rtcSession.roomId)"
                           :disabled="!baseStore.rtcSession.status.sharing">
                  复制房间号码
                </el-button>
                <el-button @click="copyToClipboard(JSON.stringify( {ice:ice,sdp:sdp,roomId:baseStore.rtcSession.roomId} ))"
                           :disabled="!baseStore.rtcSession.status.sharing">
                  复制rtc连接信息
                </el-button>
              </div>
            </el-card>
          </div>
        </el-col>
      </el-row>
    </div>
  </div>
</template>

<style scoped lang="scss">

</style>
